package com.qyl.socket_upload.example;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client {

    private static Socket socket;
    private static final int port = 123456;
    private static final String host = "***********";
    private static Logger logger;
    private static PrintStream display;
    private static DataOutputStream out;
    private static DataInputStream in;
    private static Scanner sc;

    static{
        logger = Logger.getLogger("Client");
        logger.setLevel(Level.INFO);
        display = System.out;
        sc = new Scanner(System.in);
    }
    public static void main(String[] args) {
        try {
            /* create a new object of Socket and try to connect to
             * the server with host and port
             */
            socket = new Socket(host, port);

            //logger.info("Connect to Server "+ host + " with Port "+ port);
            out = new DataOutputStream(socket.getOutputStream());
            in = new DataInputStream(socket.getInputStream());
            while(true) {
                welcomeInterface(display, sc);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * An interface that instruct users to interact with this program
     * @param display system out stream
     * @param sc system input stream
     * @throws IOException
     */
    private static void welcomeInterface(PrintStream display, Scanner sc) throws IOException {
        display.println();
        for(int i = 0; i < 15; i++) {
            display.append("#");
        }
        display.append(" Welcome To Week6Client ");
        for(int i = 0; i < 15; i++) {
            display.append("#");
        }
        display.println();
        display.println();
        display.printf("%5s%-30s", " ", "Please Enter The File Name: ");
        String fileName = sc.nextLine();
        display.println();
        fileRequest(fileName);
    }

    /**
     * send file request to server, and process responses of this request
     * from server.
     * @param fileName the name of file that expect to download
     * @throws IOException
     */
    private static void fileRequest(String fileName) throws IOException {
        StringBuffer content = new StringBuffer();
        /*
         * structure of FILE_REQUEST:
         * @command:@fileName
         */
        content.append("FILE_TRANSFER_REQUEST:");
        content.append(fileName);
        out.writeUTF(content.toString());
        out.flush();
        //logger.info("Send File Request to Server");
        // after send request to server, waiting for response from server
        String[] response = in.readUTF().split(":");
        //logger.info("Get Response From Server: " + response[0]);
        switch(response[0]) {
            case "FILE_EXISTS":
                fileName = response[1];
                File file = new File(fileName);
                /*
                 * structure of FILE_EXISTS:
                 * @Command:@FileName:@FileLength
                 */
                if(file.exists()) {
                    display.printf("%5s%s", " ", "File \"" +fileName + "\" exists in current director.\n");
                    display.printf("%5s%s", " ", "Do you want to overrid it? \n");
                    display.printf("%5s%s", " ", "Y/y -> Override, Other -> Cancel\n");
                    display.printf("%5s", " ");
                    if(!sc.nextLine().toLowerCase().equals("y")) break;
                    else {
                        file.delete();
                        file.createNewFile();
                    }
                }
                content.setLength(0);
                content.append("FILE_BYTES_REQUEST:");
                content.append(fileName);
                out.writeUTF(content.toString());
                display.printf("%5s%-30s%s", "",  "Downloading ", fileName+"\n");
                long fileLength = Long.parseLong(response[2]);
                getBytes(fileName, fileLength);
                display.printf("%5s%-20s", "",  "Download Done\n");
                break;
            case "FILE_NOT_EXISTS":
                display.printf("%5s%-50s", "", response[1]);
                break;
            default:
                break;
        }
        display.println();
        display.printf("%5s%s", " ", "Do you want to continue? \n");
        display.printf("%5s%s", " ", "Y/y -> Continue, Other -> Quit \n");
        display.printf("%5s", "");
        /*
         * if user enter other character, call stop() to close relevant
         * resources and end this process
         */
        if(!sc.nextLine().toLowerCase().equals("y")) {
            display.println();
            display.println();
            stop();
        }
        display.println();
        display.println();

    }

    /**
     * close relevant resources and call System.exit(int status) to
     * end this process
     * @throws IOException
     */
    private static void stop() throws IOException {
        out.writeUTF("DISCONNECT");
        out.close();
        in.close();
        sc.close();
        socket.close();
        System.exit(0);
    }

    /**
     * Receive bytes from server. Once the length of local file is same
     * as server's, transfer ends.
     * @param fileName the name of file that is going to operate
     * @param fileLength the length of file on server
     * @throws IOException
     */
    private static void getBytes(String fileName, long fileLength) throws IOException {
        File file = new File(fileName);
        FileOutputStream f = new FileOutputStream(file);
        byte[] bytes = new byte[1024];
        int length = 0;
        while(true) {
            length = in.read(bytes, 0, bytes.length);
            f.write(bytes, 0, length);
            f.flush();
            /*
             * when fileLength equals to length of local file, it
             * represents the downloading is finished
             */
            if(fileLength == file.length()) break;
        }
        f.close();
    }

}
